package Guigu7.Polymorphism;

/*
 * 面向对象特征之三：多态性
 * 
 * 1、理解多态性：可以理解为一个事物的多种形态。
 * 2、何为多态性：
 *   对象的多态性：父类的实例指向子类的对象(或子类的对象赋值给父类的实例)
 * 
 * 3、多态的使用：虚拟方法调用
 *   有了对象的多态性以后，我们在编译期，只能调用父类中声明的方法，但在运行期，我们实际执行的是子类重写父类的方法。
 *   总结：编译：看左边；运行：看右边。
 *   
 * 4、多态性的使用前提：① 类的继承关系 ② 方法的重写
 * 
 * 5、对象的多态性：只适用于方法，不适用于属性（编译和运行都看左边）
 */
public class PolymorphismTest {

	public static void main(String[] args) {
		
		  Perso p = new Perso();
		  p.eat();
		  
		  Man m = new Man();
		  m.eat(); 
		  m.age = 18; 
		  m.earnmoney();
		  
		  System.out.println("********************");
		  //对象的多态性：父类的引用指向子类的对象
		  Perso p1 = new Man();
		  //Perso p2 = new Moman();
		  //多态的使用：当调用子父类同名同参数的方法时，实际执行的是子类重写父类的方法---虚拟方法调用
		  p1.eat();
		  p1.walk();
		  
		  //不能调用子类中所特有的方法和属性,编译时:p1是Perso类型的,堆空间中依然加载了子类特有的方法和属性。
		  //p1.earnmoney();
		  //p1.isSmoking = true;
		  
		  //有了对象的多态性后，内存中实际上加载了子类特有的属性和方法，但是由于变量声明为父类类型，导致
		  //编译时，只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
		  
		  //如何才能调用子类特有的属性和方法？
		  //向下转型：使用强制类型转换符。
		  Man m1 = (Man)p1;
		  m1.earnmoney();
		  m1.isSmoking = true;
		  
		  //使用强转时，可能出现java.lang.ClassCastException类型转换异常
		  //Woman w1 = (Woman)p1;
		  //w1.goShopping();
		  
		  /*
		   * instanceof关键字的使用
		   * 
		   * a instanceof A :判断对象a是否是类A的实例。如果是，返回true;如果不是，返回false.
		   * 
		   * 使用情境：为了避免在向下转型时出现java.lang.ClassCastException的异常，我们在向下转型
		   *          之前。先进行instanceof的判断，一旦返回true,就进行向下转型。如果返回false,不进行向下转型
		   *          
		   * 如果 a instanceof A 返回true,则a instanceof B 也返回true。
		   * 其中，类B是类A的父类。
		   * 
		   */
		  
		  //实际进不去
//		  if(p1 instanceof Woman)
//		  {
//			  Woman w2 = (Woman)p1;
//			  w2.goShopping();
//			  System.out.println("********Woman*******");
//		  }
		  
		  if(p1 instanceof Man)
		  {
			  Man m2 = (Man)p1;
			  m2.earnmoney();
			  m2.isSmoking = true;
			  System.out.println("*********Man********");
		  }
		  
		  if(p1 instanceof Perso)
		  {
			  System.out.println("*********Person********");
		  }
		  
		  if(p1 instanceof Object)
		  {
			  System.out.println("*********Object********");
		  }
		  
		  //向下转型中常见错误
		  //问题一：编译通过，运行时不通过
//		  Perso p2 = new Woman();
//		  Man m3 =(Man)p2;
//		  
//		  Perso p3 = new Perso();
//		  Man m4 = (Man)p3;
		  
		  //问题二：编译通过，运行时也通过
		  Object obj = new Perso();
		  Perso p4 = (Perso)obj;
		  
		  //问题三：编译不通过
		  //Man m5 = new Woman();
	}
}
